﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using System.Collections;
using ProgNetComponents.Design.Attributes;
using System.ComponentModel.Design;

namespace ProgNetComponents.Design
{
    public class EventInfoDescriptor : EventDescriptor
    {
        public static EventDescriptorCollection GetEvents(object target)
        {
            try
            {
                EventDescriptorCollection oryginal = TypeDescriptor.GetEvents(target.GetType());
                EventInfo[] infos = null;
                List<EventInfo> pList = new List<EventInfo>();
                Type t = target.GetType();
                List<string> strList = new List<string>();

                List<EventDescriptor> list = new List<EventDescriptor>();
                while (t != typeof(Object) && t != null)
                {
                    infos = t.GetEvents(BindingFlags.Public | BindingFlags.Instance);
                    pList.Clear();
                    pList.AddRange(infos);

                    foreach (EventInfo info in pList)
                    {
                        if (!strList.Contains(info.Name))
                        {
                            strList.Add(info.Name);
                            ArrayList attributeList = new ArrayList();
                            bool changedAttribute = false;
                            foreach (Attribute attrib in info.GetCustomAttributes(true))
                            {
                                if (attrib is IDynamicAttribute)
                                {
                                    changedAttribute = true;
                                    Attribute a = ((IDynamicAttribute)attrib).GetRealAttribute(target);
                                    if (a != null)
                                        attributeList.Add(a);
                                }
                                else
                                    attributeList.Add(attrib);
                            }
                            if (changedAttribute)
                                list.Add(new EventInfoDescriptor(info, (Attribute[])attributeList.ToArray(typeof(Attribute))));
                        }
                    }
                    t = t.BaseType;
                }
                
                bool found = false;
                for (int i = 0; i < oryginal.Count; i++)
                {
                    found = false;
                    for (int j = 0; j < list.Count; j++)
                    {
                        if (list[j].Name == oryginal[i].Name)
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                        list.Add(oryginal[i]);
                }
                
                return new EventDescriptorCollection(list.ToArray(), false);
            }
            catch (Exception ex)
            {
                ex.Log();
            }
            return TypeDescriptor.GetEvents(target, false);
        }

        private EventInfo _Info;

        public EventInfoDescriptor(EventInfo info, Attribute[] attribs)
            : base(info.Name, attribs)
        {
            _Info = info;
        }

        public override void AddEventHandler(object component, Delegate value)
        {
            if (component != null)
            {
                ISite site = MemberDescriptor.GetSite(component);
                IComponentChangeService service = null;
                if (site != null)
                {
                    service = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
                }
                if (service != null)
                {
                    try
                    {
                        service.OnComponentChanging(component, this);
                    }
                    catch (CheckoutException exception)
                    {
                        if (exception != CheckoutException.Canceled)
                        {
                            throw exception;
                        }
                        return;
                    }
                }
                bool flag = false;
                if ((site != null) && site.DesignMode)
                {
                    if (this.EventType != value.GetType())
                    {
                        throw new ArgumentException("Invalid event type");
                    }
                    IDictionaryService service2 = (IDictionaryService)site.GetService(typeof(IDictionaryService));
                    if (service2 != null)
                    {
                        Delegate a = (Delegate)service2.GetValue(this);
                        a = Delegate.Combine(a, value);
                        service2.SetValue(this, a);
                        flag = true;
                    }
                }
                if (!flag)
                {
                    _Info.AddEventHandler(component,  value);
                }
                if (service != null)
                {
                    service.OnComponentChanged(component, this, null, value);
                }
            }

        }

        public override Type ComponentType
        {
            get { return _Info.DeclaringType; }
        }

        public override Type EventType
        {
            get { return _Info.EventHandlerType; }
        }

        public override bool IsMulticast
        {
            get { return _Info.IsMulticast; }
        }

        public override void RemoveEventHandler(object component, Delegate value)
        {
            if (component != null)
            {
                ISite site = MemberDescriptor.GetSite(component);
                IComponentChangeService service = null;
                if (site != null)
                {
                    service = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
                }
                if (service != null)
                {
                    try
                    {
                        service.OnComponentChanging(component, this);
                    }
                    catch (CheckoutException exception)
                    {
                        if (exception != CheckoutException.Canceled)
                        {
                            throw exception;
                        }
                        return;
                    }
                }
                bool flag = false;
                if ((site != null) && site.DesignMode)
                {
                    IDictionaryService service2 = (IDictionaryService)site.GetService(typeof(IDictionaryService));
                    if (service2 != null)
                    {
                        Delegate source = (Delegate)service2.GetValue(this);
                        source = Delegate.Remove(source, value);
                        service2.SetValue(this, source);
                        flag = true;
                    }
                }
                if (!flag)
                {
                    _Info.RemoveEventHandler(component, value);
                }
                if (service != null)
                {
                    service.OnComponentChanged(component, this, null, value);
                }
            }

        }
    }
}
